/*     */ package com.zimbra.cs.service.formatter;
/*     */ 
/*     */ import com.zimbra.common.localconfig.KnownKey;
/*     */ import com.zimbra.common.localconfig.LC;
/*     */ import com.zimbra.common.mime.MimeDetect;
/*     */ import com.zimbra.common.service.ServiceException;
/*     */ import com.zimbra.common.util.ByteUtil;
/*     */ import com.zimbra.common.util.HttpUtil;
/*     */ import com.zimbra.common.util.HttpUtil.Browser;
/*     */ import com.zimbra.common.util.Log;
/*     */ import com.zimbra.common.util.LogFactory;
/*     */ import com.zimbra.cs.account.Account;
/*     */ import com.zimbra.cs.mailbox.Document;
/*     */ import com.zimbra.cs.mailbox.Folder;
/*     */ import com.zimbra.cs.mailbox.MailItem;
/*     */ import com.zimbra.cs.mailbox.MailItem.Type;
/*     */ import com.zimbra.cs.mailbox.MailServiceException;
/*     */ import com.zimbra.cs.mailbox.MailServiceException.NoSuchItemException;
/*     */ import com.zimbra.cs.mailbox.Mailbox;
/*     */ import com.zimbra.cs.mime.ParsedDocument;
/*     */ import com.zimbra.cs.octosync.PatchException;
/*     */ import com.zimbra.cs.octosync.PatchInputStream;
/*     */ import com.zimbra.cs.octosync.store.BlobStore;
/*     */ import com.zimbra.cs.octosync.store.PatchStore;
/*     */ import com.zimbra.cs.octosync.store.PatchStore.IncomingPatch;
/*     */ import com.zimbra.cs.octosync.store.PatchStore.StoredPatch;
/*     */ import com.zimbra.cs.octosync.store.StoreManagerBasedTempBlobStore;
/*     */ import com.zimbra.cs.service.UserServletContext;
/*     */ import com.zimbra.cs.service.UserServletException;
/*     */ import com.zimbra.cs.service.mail.UploadScanner;
/*     */ import com.zimbra.cs.service.mail.UploadScanner.Result;
/*     */ import com.zimbra.cs.store.Blob;
/*     */ import com.zimbra.cs.store.StoreManager;
/*     */ import java.io.FileNotFoundException;
/*     */ import java.io.IOException;
/*     */ import java.io.InputStream;
/*     */ import java.io.SequenceInputStream;
/*     */ import java.util.Map;
/*     */ import javax.servlet.ServletException;
/*     */ import javax.servlet.http.HttpServletRequest;
/*     */ import javax.servlet.http.HttpServletResponse;
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ public class OctopusPatchFormatter
/*     */   extends Formatter
/*     */ {
/*  63 */   private static final Log log = LogFactory.getLog(OctopusPatchFormatter.class);
/*     */   
/*     */   private PatchStore patchStore;
/*     */   
/*     */   OctopusPatchFormatter()
/*     */   {
/*  69 */     long incomingPatchExpiration = LC.octopus_incoming_patch_max_age.intValue() * 60 * 1000;
/*  70 */     long storedPatchExpiration = LC.octopus_stored_patch_max_age.intValue() * 60 * 1000;
/*     */     
/*  72 */     BlobStore blobStore = new StoreManagerBasedTempBlobStore(StoreManager.getInstance(), incomingPatchExpiration, storedPatchExpiration, true);
/*     */     
/*     */ 
/*  75 */     this.patchStore = new PatchStore(blobStore);
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */   public FormatterFactory.FormatType getType()
/*     */   {
/*  82 */     return FormatterFactory.FormatType.OPATCH;
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */   public boolean supportsSave()
/*     */   {
/*  89 */     return true;
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */   public void saveCallback(UserServletContext context, String contentType, Folder folder, String filename)
/*     */     throws IOException, ServiceException, UserServletException
/*     */   {
/*  99 */     log.info("Uploading patch for " + filename);
/*     */     
/* 101 */     if (filename == null) {
/* 102 */       throw new UserServletException(400, "Missing filename");
/*     */     }
/*     */     
/* 105 */     MailItem item = null;
/* 106 */     Mailbox mbox = folder.getMailbox();
/*     */     try
/*     */     {
/* 109 */       item = mbox.getItemByPath(context.opContext, filename, folder.getId());
/*     */       
/* 111 */       if (!(item instanceof Document)) {
/* 112 */         throw new UserServletException(400, "cannot overwrite existing object at that path");
/*     */       }
/*     */     } catch (MailServiceException.NoSuchItemException e) {
/* 115 */       log.debug("No document found at " + filename + "(folder id=" + folder.getId() + "; will create new one");
/*     */     }
/*     */     
/*     */ 
/* 119 */     PatchInputStream pis = null;
/* 120 */     PatchStore.IncomingPatch ip = null;
/*     */     try
/*     */     {
/* 123 */       ip = this.patchStore.createIncomingPatch(context.targetAccount.getId());
/*     */       
/* 125 */       int defaultFileId = 0;
/* 126 */       int defaultVersion = 0;
/*     */       
/* 128 */       if (item != null) {
/* 129 */         defaultFileId = item.getId();
/* 130 */         defaultVersion = item.getVersion();
/*     */       }
/*     */       
/* 133 */       pis = PatchInputStream.create(context.getRequestInputStream(), context.targetMailbox, context.opContext, defaultFileId, defaultVersion, ip.getOutputStream(), ip.getManifest());
/*     */       
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/* 144 */       String creator = context.getAuthAccount() == null ? null : context.getAuthAccount().getName();
/*     */       
/* 146 */       if (contentType == null) {
/* 147 */         contentType = MimeDetect.getMimeDetect().detect(filename);
/* 148 */         if (contentType == null) {
/* 149 */           contentType = "application/octet-stream";
/*     */         }
/*     */       }
/* 152 */       log.debug("Storing blob");
/* 153 */       Blob blob = StoreManager.getInstance().storeIncoming(pis);
/*     */       
/* 155 */       log.debug("Creating parsed document; filename=" + filename + ", contentType=" + contentType + ", creator=" + creator);
/*     */       
/*     */ 
/* 158 */       ParsedDocument pd = new ParsedDocument(blob, filename, contentType, System.currentTimeMillis(), creator, context.req.getHeader("X-Zimbra-Description"), true);
/*     */       
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/* 167 */       log.debug("Parsed document created " + filename);
/*     */       
/*     */ 
/* 170 */       StringBuffer info = new StringBuffer();
/* 171 */       UploadScanner.Result result = UploadScanner.acceptStream(pis, info);
/* 172 */       if (result == UploadScanner.REJECT)
/* 173 */         throw MailServiceException.UPLOAD_REJECTED(filename, info.toString());
/* 174 */       if (result == UploadScanner.ERROR) {
/* 175 */         throw MailServiceException.SCAN_ERROR(filename);
/*     */       }
/* 177 */       if (item == null) {
/* 178 */         log.debug("Creating new document " + filename);
/* 179 */         item = mbox.createDocument(context.opContext, folder.getId(), pd, MailItem.Type.DOCUMENT, 0);
/*     */       } else {
/* 181 */         log.debug("Creating new version of the document " + filename + ", current version: " + item.getVersion());
/*     */         
/* 183 */         item = mbox.addDocumentRevision(context.opContext, item.getId(), pd);
/*     */       }
/*     */       
/* 186 */       this.patchStore.acceptPatch(ip, item.getId(), item.getVersion());
/*     */       
/* 188 */       NativeFormatter.sendZimbraHeaders(context, context.resp, item); return;
/*     */     }
/*     */     catch (PatchException e) {
/* 191 */       log.error("Patch upload failed: " + e);
/*     */       
/* 193 */       this.patchStore.rejectPatch(ip);
/*     */       
/* 195 */       throw new UserServletException(409, "patch cannot be applied, try uploading whole file", e);
/*     */     }
/*     */     finally {
/*     */       try {
/* 199 */         pis.close();
/*     */       } catch (Exception e) {
/* 201 */         log.error("Exception during PatchInputStream close, ignored: " + e);
/*     */       }
/*     */     }
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */   public void formatCallback(UserServletContext context)
/*     */     throws UserServletException, ServiceException, IOException, ServletException
/*     */   {
/* 211 */     if (!(context.target instanceof Document)) {
/* 212 */       throw UserServletException.notImplemented("can only handle documents");
/*     */     }
/*     */     
/* 215 */     Document doc = (Document)context.target;
/*     */     
/* 217 */     String v = (String)context.params.get("ver");
/* 218 */     int version = v != null ? Integer.parseInt(v) : -1;
/*     */     
/* 220 */     if (log.isDebugEnabled()) {
/* 221 */       log.debug("Request received for patch for " + doc.getName() + ", id: " + doc.getId() + (version == -1 ? ", latest version" : new StringBuilder().append(", version: ").append(version).toString()));
/*     */     }
/*     */     
/*     */ 
/* 225 */     NativeFormatter.sendZimbraHeaders(context, context.resp, context.target);
/*     */     
/* 227 */     HttpUtil.Browser browser = HttpUtil.guessBrowser(context.req);
/* 228 */     if (browser == HttpUtil.Browser.IE) {
/* 229 */       context.resp.addHeader("X-Content-Type-Options", "nosniff");
/*     */     }
/*     */     
/* 232 */     if (version > 0) {
/* 233 */       doc = (Document)doc.getMailbox().getItemRevision(context.opContext, doc.getId(), doc.getType(), version);
/*     */     } else {
/* 235 */       version = doc.getVersion();
/*     */       
/* 237 */       if (log.isDebugEnabled()) {
/* 238 */         log.debug("Latest version of " + doc.getName() + " is " + version);
/*     */       }
/*     */     }
/*     */     
/* 242 */     PatchStore.StoredPatch sp = this.patchStore.lookupPatch(context.targetAccount.getId(), doc.getId(), version);
/*     */     
/* 244 */     if (sp != null) {
/* 245 */       sendPatch(context, doc, version, sp);
/*     */     } else {
/* 247 */       if (log.isDebugEnabled()) {
/* 248 */         log.debug("Patch not available for " + doc.getName() + ", id: " + doc.getId() + ", version: " + version + "; will return the entire file");
/*     */       }
/*     */       
/* 251 */       sendFullFile(context, doc, version);
/*     */     }
/*     */   }
/*     */   
/*     */   private void sendPatch(UserServletContext context, Document doc, int version, PatchStore.StoredPatch sp) throws IOException, ServiceException
/*     */   {
/* 257 */     InputStream patchIs = null;
/* 258 */     InputStream manifestIs = null;
/*     */     
/* 260 */     String manifestParam = (String)context.params.get("manifest");
/*     */     
/* 262 */     boolean sendManifest = Integer.parseInt(manifestParam) > 0;
/*     */     try
/*     */     {
/* 265 */       patchIs = sp.getInputStream();
/* 266 */       if (sendManifest) {
/* 267 */         manifestIs = sp.getManifestInputStream();
/*     */       }
/*     */     } catch (FileNotFoundException e) {
/* 270 */       log.warn("Cannot access patch for " + doc.getName() + ", id: " + doc.getId() + ", version: " + version + "; will return the entire file (failure: " + e + ")");
/*     */       
/*     */ 
/* 273 */       sendFullFile(context, doc, version);
/* 274 */       return;
/*     */     }
/*     */     
/* 277 */     if (log.isDebugEnabled()) {
/* 278 */       log.debug("Sending patch for " + doc.getName() + ", id: " + doc.getId() + ", version: " + version);
/*     */     }
/*     */     
/*     */ 
/* 282 */     context.resp.addIntHeader("X-Octopus-Patch", 1);
/*     */     
/* 284 */     InputStream is = null;
/*     */     
/* 286 */     if (sendManifest) {
/* 287 */       context.resp.setContentLength((int)(sp.getPatchSize() + sp.getManifestSize()));
/* 288 */       assert (manifestIs != null);
/* 289 */       is = new SequenceInputStream(manifestIs, patchIs);
/*     */     } else {
/* 291 */       context.resp.setContentLength((int)sp.getPatchSize());
/* 292 */       is = patchIs;
/*     */     }
/*     */     
/* 295 */     ByteUtil.copy(is, true, context.resp.getOutputStream(), false);
/*     */   }
/*     */   
/*     */   private void sendFullFile(UserServletContext context, Document doc, int version)
/*     */     throws ServiceException, IOException
/*     */   {
/* 301 */     context.resp.addIntHeader("X-Octopus-Patch", 0);
/*     */     
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/* 308 */     context.resp.setContentLength((int)doc.getSize());
/*     */     
/* 310 */     InputStream is = doc.getContentStream();
/* 311 */     ByteUtil.copy(is, true, context.resp.getOutputStream(), false);
/*     */   }
/*     */ }


/* Location:              /home/mint/zimbrastore.jar!/com/zimbra/cs/service/formatter/OctopusPatchFormatter.class
 * Java compiler version: 7 (51.0)
 * JD-Core Version:       0.7.1
 */